package UI;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.TableColumn;

import threads.BaseRunnableBCBS;
import Logic.Account;
import Logic.SQLReader;
import UI.BaseModels.BCBSPanel;
import UI.BaseModels.HeaderLabel;
import UI.BaseModels.ReturnToAdminMenuButton;
import UI.TableModels.TableModelTransactions;

/**
 * Contains all the buttons, labels, text fields and methods required to edit a
 * user.
 */

public class EditUserPanel extends BCBSPanel {

	private static final long serialVersionUID = 1197251940543681656L;
	private JTextField usernameValue;
	private JLabel firstnameValue;
	private JLabel lastnameValue;
	private JLabel balanceValue;
	private JLabel lblActive;
	private JLabel lblInactive;
	private JButton btnGetInfo;
	private JButton btnDeactivateUser;
	private JButton btnActivateUser;
	private JTable transactionTable;
	private Account selectedAccount;

	private int gotTransactionsUntil;

	private TableModelTransactions tablemodel;

	public EditUserPanel() {

		gotTransactionsUntil = 2147483647; // Initially get transactions with ID
											// below maximum int size. Then load
											// more until no lower IDs can be
											// found in SQL.

		HeaderLabel header = new HeaderLabel("User Management");
		this.add(header);

		ReturnToAdminMenuButton rtmm = new ReturnToAdminMenuButton();
		this.add(rtmm);

		JLabel lblUsername = new JLabel("Username");
		lblUsername.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblUsername.setBounds(10, 40, 110, 25);
		add(lblUsername);

		usernameValue = new JTextField();
		usernameValue.setHorizontalAlignment(SwingConstants.CENTER);
		usernameValue.setBounds(125, 42, 165, 25);
		usernameValue.getDocument().addDocumentListener(new ClearFields());
		add(usernameValue);
		usernameValue.setColumns(10);
		usernameValue.addActionListener(new GetUser());

		JLabel lblBalance = new JLabel("Balance");
		lblBalance.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblBalance.setBounds(10, 148, 110, 25);
		add(lblBalance);

		JLabel lblFirstName = new JLabel("First name");
		lblFirstName.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblFirstName.setBounds(10, 76, 110, 25);
		add(lblFirstName);

		balanceValue = new JLabel("");
		balanceValue.setHorizontalAlignment(SwingConstants.CENTER);
		balanceValue.setFont(new Font("Tahoma", Font.PLAIN, 12));
		balanceValue.setBounds(125, 148, 165, 25);
		add(balanceValue);

		firstnameValue = new JLabel("");
		firstnameValue.setHorizontalAlignment(SwingConstants.CENTER);
		firstnameValue.setFont(new Font("Tahoma", Font.PLAIN, 12));
		firstnameValue.setBounds(125, 76, 165, 25);
		add(firstnameValue);

		JLabel lblLastName = new JLabel("Last name");
		lblLastName.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblLastName.setBounds(10, 112, 110, 25);
		add(lblLastName);

		lastnameValue = new JLabel("");
		lastnameValue.setHorizontalAlignment(SwingConstants.CENTER);
		lastnameValue.setFont(new Font("Tahoma", Font.PLAIN, 12));
		lastnameValue.setBounds(125, 112, 165, 25);
		add(lastnameValue);

		btnDeactivateUser = new JButton("Deactivate");
		btnDeactivateUser.setBounds(158, 328, 117, 29);
		btnDeactivateUser.addActionListener(new DeactivateUser());
		btnDeactivateUser.setEnabled(false);
		btnDeactivateUser.setVisible(false);
		add(btnDeactivateUser);

		JLabel lblTransactions = new JLabel("Transactions");
		lblTransactions.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblTransactions.setBounds(10, 220, 110, 25);
		add(lblTransactions);

		JLabel lblStatus = new JLabel("Status");
		lblStatus.setFont(new Font("Tahoma", Font.PLAIN, 15));
		lblStatus.setBounds(10, 184, 110, 25);
		add(lblStatus);

		lblActive = new JLabel("Active");
		lblActive.setHorizontalAlignment(SwingConstants.CENTER);
		lblActive.setFont(new Font("Tahoma", Font.PLAIN, 12));
		lblActive.setForeground(new Color(0, 128, 0));
		lblActive.setBounds(125, 184, 165, 25);
		add(lblActive);
		lblActive.setVisible(false);

		lblInactive = new JLabel("Inactive");
		lblInactive.setHorizontalAlignment(SwingConstants.CENTER);
		lblInactive.setFont(new Font("Tahoma", Font.PLAIN, 12));
		lblInactive.setForeground(Color.RED);
		lblInactive.setBounds(125, 184, 165, 25);
		lblInactive.setVisible(false);
		add(lblInactive);

		btnGetInfo = new JButton("Get Info");
		btnGetInfo.setBounds(21, 328, 117, 29);
		btnGetInfo.addActionListener(new GetUser());
		add(btnGetInfo);

		feedbackLabel.setLocation(0, 368);

		btnActivateUser = new JButton("Activate");
		btnActivateUser.addActionListener(new ActivateUser());
		btnActivateUser.setBounds(158, 328, 117, 29);
		btnActivateUser.setEnabled(false);
		btnActivateUser.setVisible(false);
		add(btnActivateUser);
		lblInactive.setVisible(false);

		transactionTable = new JTable();
		transactionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		transactionTable.setRowSelectionAllowed(true);
		transactionTable.setBorder(new BevelBorder(BevelBorder.LOWERED, null,
				null, null, null));
		tablemodel = new TableModelTransactions();
		transactionTable.setModel(tablemodel);

		TableColumn col1 = transactionTable.getColumnModel().getColumn(0);
		TableColumn col2 = transactionTable.getColumnModel().getColumn(1);
		TableColumn col3 = transactionTable.getColumnModel().getColumn(2);

		col1.setPreferredWidth(165);
		col2.setPreferredWidth(55);
		col3.setPreferredWidth(90);

		transactionTable.setBounds(0, 51, 305, 230);
		transactionTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
		transactionTable.setTableHeader(null);

		JScrollPane scrollpane = new JScrollPane(transactionTable);
		scrollpane.setViewportBorder(null);
		scrollpane
				.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

		scrollpane.setBounds(0, 245, 305, 72);
		scrollpane.setVisible(true);
		this.add(scrollpane);

	}

	private class DeactivateUser implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			deactivateUser();
		}
	}

	private class GetUser implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			getUserInfo(null);
		}
	}

	private class ActivateUser implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			activateUser();
		}
	}

	private class ClearFields implements DocumentListener {

		@Override
		public void insertUpdate(DocumentEvent e) {
			// clearFieldsLocal();

		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			clearFieldsLocal();

		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			// clearFieldsLocal();

		}
	}

	/**
	 * Clears all text fields, deactivates the deactivate/activate button,
	 * clears the JTable and resets the transaction tracker variable to the
	 * maximum allowed value for integers.
	 */
	@Override
	public void clearFields() {
		usernameValue.setText(""); // cannot be cleared by private method.
									// Mutation.
		feedbackLabel.setText("");
		firstnameValue.setText("");
		lastnameValue.setText("");
		balanceValue.setText("");
		btnActivateUser.setEnabled(false);
		btnActivateUser.setVisible(false);
		btnDeactivateUser.setEnabled(false);
		btnDeactivateUser.setVisible(false);
		btnGetInfo.setEnabled(true);
		lblInactive.setVisible(false);
		lblActive.setVisible(false);
		tablemodel.clearTable();
		gotTransactionsUntil = 2147483647;
	}

	/**
	 * Private method used to clear the table without removing the username from
	 * the username field or resetting the tracker variable.
	 */

	private void clearFieldsLocal() {
		feedbackLabel.setText("");
		firstnameValue.setText("");
		lastnameValue.setText("");
		balanceValue.setText("");
		btnActivateUser.setEnabled(false);
		btnActivateUser.setVisible(false);
		btnDeactivateUser.setEnabled(false);
		btnDeactivateUser.setVisible(false);
		btnGetInfo.setEnabled(true);
		lblInactive.setVisible(false);
		lblActive.setVisible(false);
		tablemodel.clearTable();
	}

	public final TableModelTransactions getTableModel() {
		return this.tablemodel;
	}

	public final int getLowestTransactionID() {
		return this.gotTransactionsUntil;
	}

	public final void setLowestTransactionID(int id) {
		this.gotTransactionsUntil = id;
	}

	public final void setFirstname(String firstnameValue) {
		this.firstnameValue.setText(firstnameValue);
	}

	public final void setLastname(String lastnameValue) {
		this.lastnameValue.setText(lastnameValue);
	}

	public final void setBalance(String balanceValue) {
		this.balanceValue.setText(balanceValue);
	}

	public final String getEmail() {
		return this.usernameValue.getText().trim();
	}

	/**
	 * Enables or disables the buttons based on the parameter supplied.
	 * 
	 * @param value
	 *            If the value is true, the buttons are enabled, if the value is
	 *            false, the buttons are disabled.
	 */
	public final void enableButtons(boolean value) {
		if (value) {
			btnGetInfo.setEnabled(true);
			btnActivateUser.setEnabled(true);
			btnDeactivateUser.setEnabled(true);
		} else {
			btnGetInfo.setEnabled(false);
			btnActivateUser.setEnabled(false);
			btnDeactivateUser.setEnabled(false);
		}
	}

	/**
	 * Configures the combination of the deactivate/activate button and the
	 * Active/Inactive label.
	 * 
	 * @param value
	 *            If the value is true, configures the interface for
	 *            deactivating the user, if false, configures the user interface
	 *            for activating the user.
	 */
	public final void setActiveLabelButton(boolean value) {
		if (value) {
			btnActivateUser.setVisible(false);
			btnActivateUser.setEnabled(false);
			btnDeactivateUser.setVisible(true);
			btnDeactivateUser.setEnabled(true);
			lblInactive.setVisible(false);
			lblActive.setVisible(true);
		} else {
			btnActivateUser.setVisible(true);
			btnActivateUser.setEnabled(true);
			btnDeactivateUser.setVisible(false);
			btnDeactivateUser.setEnabled(false);
			btnActivateUser.setVisible(true);
			btnDeactivateUser.setVisible(false);
			lblInactive.setVisible(true);
			lblActive.setVisible(false);
		}
	}

	/**
	 * Creates a new Runnable of the type GetUserInfoRunnable, sets it to the
	 * current runnable for the panel, places it in its own thread and runs it.
	 * Sets the selectedAccount variable to the account supplied
	 * 
	 * @param acc
	 *            The supplied account to fetch info for.
	 */
	public void getUserInfo(Account acc) {
		selectedAccount = acc;
		runnable = new GetUserInfoRunnable();
		Thread t = new Thread(runnable);
		t.start();

	}

	/**
	 * Creates a new Runnable of the type ActivateUserRunnable, sets it to the
	 * current runnable for the panel, places it in its own thread and runs it.
	 */
	public void activateUser() {
		runnable = new ActivateUserRunnable();
		Thread t = new Thread(runnable);
		t.start();
	}

	/**
	 * Creates a new Runnable of the type DeactivateUserRunnable, sets it to the
	 * current runnable for the panel, places it in its own thread and runs it.
	 */
	public void deactivateUser() {
		runnable = new DeactivateUserRunnable();
		Thread t = new Thread(runnable);
		t.start();
	}

	/**
	 * See the run-method of this class for details.
	 * 
	 */
	private class DeactivateUserRunnable extends BaseRunnableBCBS {
		/**
		 * Checks for valid input in the SQL database and if successful,
		 * deactivates user. Throws feedback according to result.
		 * 
		 */
		public void run() {
			SQLReader reader = new SQLReader();
			feedback("Loading....", true);
			String email = "";
			boolean emailExists = false;
			boolean validated = false;
			enableButtons(false);
			email = getEmail();
			try {
				if (!stop) {
					emailExists = reader.checkEmail(email);
					validated = true;
				}
			} catch (SQLException e) {
				if (!stop) {
					enableButtons(true);
					feedback("Connection error! Try again!", false);
				}
			}
			if (emailExists && validated && !stop) {
				try {
					reader.disableAccount(reader.getUserID(email));
					if (!stop) {
						feedback("User deactivated!", true);
						setActiveLabelButton(false);
						enableButtons(true);
					}
				} catch (SQLException e) {
					if (!stop) {
						enableButtons(true);
						feedback("Connection error! Try again!", false);
					}
				}

			} else if (!stop && validated) {
				enableButtons(true);
				feedback("User does not exist!", false);
			}
		}

	}

	/**
	 * See the run-method of this class for details.
	 * 
	 */
	private class ActivateUserRunnable extends BaseRunnableBCBS {
		/**
		 * Checks for valid input in the SQL database and if successful,
		 * activates user. Throws feedback according to result.
		 * 
		 */
		public void run() {
			SQLReader reader = new SQLReader();
			feedback("Loading....", true);
			boolean emailExists = false;
			boolean validated = false;
			String email = "";
			enableButtons(false);

			email = getEmail();

			try {
				if (!stop) {
					emailExists = reader.checkEmailAll(email);
					validated = true;
				}
			} catch (SQLException e) {
				if (!stop) {
					enableButtons(true);
				}
			}
			if (emailExists && validated && !stop) {
				try {
					reader.enableAccount(reader.getUserID(email));
					if (!stop) {
						feedback("User reactivated!", true);
						enableButtons(true);
						setActiveLabelButton(true);
					}
				} catch (SQLException e) {
					if (!stop) {
						enableButtons(true);
						feedback("Connection error!", false);
					}
				}

			} else if (!stop && validated) {

				enableButtons(true);
				feedback("User does not exist!", false);

			}

		}
	}

	/**
	 * See the run-method of this class for details.
	 * 
	 */
	private class GetUserInfoRunnable extends BaseRunnableBCBS {
		/**
		 * Searches for account according to input. Gets user information from
		 * the SQL database.
		 * 
		 * Throws feedback according to result.
		 * 
		 */
		public void run() {
			SQLReader reader = new SQLReader();
			feedback("Loading....", true);
			boolean userexists = false;
			boolean validated = false;
			String username = "";
			if (selectedAccount != null) {
				username = selectedAccount.getEmail();
				usernameValue.setText(selectedAccount.getEmail());
				selectedAccount = null;
			} else {
				username = getEmail();
			}
			if (!username.isEmpty()) {
				feedback("Loading...", true);
				enableButtons(false);
				if (!stop) {
					try {
						userexists = reader.checkEmailAll(username);
						validated = true;
					} catch (SQLException e) {
						if (!stop) {
							feedback("Connection error!", false);
							enableButtons(true);
						}
					}

					if (userexists && validated && !stop) {
						Account user;
						try {
							user = reader
									.getAccount(reader.getUserID(username));
							if (!stop) {
								setLowestTransactionID(getTableModel()
										.refreshData(
												reader.getTransactions(
														user.getId(),
														2147483647)));
							}
							if (!stop) {
								clearFeedback();
								setFirstname(user.getFirstname());
								setLastname(user.getLastname());
								setBalance(String.valueOf(user.getBalance()));
								if (user.isDeactivated()) {
									setActiveLabelButton(false);
								} else {
									setActiveLabelButton(true);
								}
								enableButtons(true);
								clearFeedback();
							}
						} catch (SQLException e) {
							if (!stop) {
								feedback("Connection error! Try again!", false);
								enableButtons(true);
							}
						}
					} else if (!stop && validated) {
						feedback("User does not exist!", false);
						enableButtons(true);
					}
				}
			} else {
				feedback("Please input a username!", false);
			}
		}
	}

}